<?php

#############################################################################
# IMDBPHP                              (c) Giorgos Giagas & Itzchak Rehberg #
# written by Giorgos Giagas                                                 #
# extended & maintained by Itzchak Rehberg <izzysoft@qumran.org>            #
# http://www.qumran.org/homes/izzy/                                         #
# ------------------------------------------------------------------------- #
# This program is free software; you can redistribute and/or modify it      #
# under the terms of the GNU General Public License (see doc/LICENSE)       #
#############################################################################

/* $Id: imdb.class.php,v 1.13 2007/10/05 00:07:03 izzy Exp $ */

require_once ("include/browser/browseremulator.class.php");
require_once ("include/browser/info_extractor.php");
require_once (dirname(__FILE__) . "/imdb_config.php");

#===============================================[ The IMDB class itself ]===
/** Accessing IMDB information
 * @package Api
 * @class imdb
 * @extends imdb_config
 * @author Izzy (izzysoft@qumran.org)
 * @copyright (c) 2002-2004 by Giorgos Giagas and (c) 2004-2007 by Itzchak Rehberg and IzzySoft
 * @version $Revision: 1.13 $ $Date: 2007/10/05 00:07:03 $
 */

class imdb extends imdb_config {

	var $imdbID = "";
	var $page;
	var $main_title = "";
	var $main_year = "";
	var $main_runtime = "";
	var $main_runtimes;
	var $main_rating = "";
	var $main_votes = "";
	var $main_language = "";
	var $main_languages = "";
	var $main_genre = "";
	var $main_genres = "";
	var $main_tagline = "";
	var $main_plotoutline = "";
	var $main_comment = "";
	var $main_alttitle = "";
	var $main_colors = "";
	var $plot_plot = "";
	var $taglines = "";
	var $credits_cast = "";
	var $credits_director = "";
	var $credits_writing = "";
	var $credits_producer = "";
	var $main_director = "";
	var $main_credits = "";
	var $main_photo = "";
	var $main_country = "";
	var $main_alsoknow = "";
	var $main_sound = "";
	var $info_excer;
	var $similiar_movies = array(array('Name' => '', 'Link' => '', 'Local' => '')); // no Thumbnail here, since it works different from last.fm, douban
	var $extension = array('Title', 'Credits', 'Amazon', 'Goofs', 'Plot', 'Comments', 'Quotes', 'Taglines', 'Plotoutline', 'Trivia', 'Directed');

	function debug_scalar($scalar) {
		echo "<b><font color='#ff0000'>$scalar</font></b><br>";
	}

	function debug_object($object) {
		echo "<font color='#ff0000'><pre>";
		print_r($object);
		echo "</pre></font>";
	}

	function debug_html($html) {
		echo "<b><font color='#ff0000'>" . htmlentities($html) . "</font></b><br>";
	}

	/** Get similiar movies
	 * @method similiar_movies
	 * @return list similiar_movies
	 */
	function similiar_movies() {
		if (!isset($this->similiar_movies)) {
			if ($this->page["Title"] == "") {
				$this->openpage("Title");
			}
			$similiar_movies = $this->info_excer->truncate($this->page["Title"], "<h3>Recommendations</h3>", "<tr class=\"rating\">");
			$similiar_movies = $this->info_excer->truncate($similiar_movies, "<tr>", "</tr>");
			$res_where_array = array('Link' => '1', 'Name' => '3');
			if ($res_array = $this->info_excer->find_pattern($similiar_movies, "/<td><a href=\"((\s|.)+?)\">((\s|.)+?)<\/a><\/td>/", true, $res_where_array)) {
				$counter = 0;
				foreach ($res_array as $res_array_each) {
					$this->similiar_movies[$counter]['Link'] = $res_array_each[0];
					$this->similiar_movies[$counter]['Name'] = $res_array_each[1];

					$imdb_id = ltrim(strrchr($res_array_each[0], 'tt'), 'tt');
					$imdb_id = preg_replace("/[^A-Za-z0-9]/", "", $imdb_id);

					//die("ss" . $imdb_id);
					$imdb_sim_movies = new imdb($imdb_id);
					//$imdb_sim_movies->setid($imdb_id);
					//$target = array('Title', 'Credits', 'Plot');
					$target = array('Title');
					$imdb_sim_movies->preparecache($target, false);
					$this->similiar_movies[$counter]['Local'] = $imdb_sim_movies->photo_localurl();
					$counter++;
				}
			}
		}
		return $this->similiar_movies;
	}

	/** Test if IMDB url is valid
	 * @method urlstate ()
	 * @param none
	 * @return int state (0-not valid, 1-valid)
	 */
	function urlstate() {
		if (strlen($this->imdbID) != 7)
			return 0;
		else
			return 1;
	}

	/** Test if caching IMDB page is complete
	 * @method cachestate ()
	 * @param $target array
	 * @return int state (0-not complete, 1-cache complete, 2-cache not enabled, 3-not valid imdb url)
	 */
	function cachestate($target = "") {
		if (strlen($this->imdbID) != 7) {
			//echo "not valid imdbID: ".$this->imdbID."<BR>".strlen($this->imdbID);
			$this->page[$wt] = "不能打开页面";
			return 3;
		}
		if ($this->usecache) {
			$ext_arr = isset($target) ? $target : $this->extension;
			foreach ($ext_arr as $ext) {
				if (!file_exists("$this->cachedir/$this->imdbID.$ext"))
					return 0;
				@$fp = fopen("$this->cachedir/$this->imdbID.$ext", "r");
				if (!$fp)
					return 0;
			}
			return 1;
		} else
			return 2;
	}

	/** prepare IMDB page cache
	 * @method preparecache
	 * @param $target array
	 */
	function preparecache($target = "", $retrive_similiar = false) {
		$ext_arr = isset($target) ? $target : $this->extension;
		foreach ($ext_arr as $ext) {
			$tar_ext = array($ext);
			if ($this->cachestate($tar_ext) == 0)
				$this->openpage($ext);
		}
		if ($retrive_similiar)
			$this->similiar_movies(false);
		return $ext;
	}

	/** Open an IMDB page
	 * @method openpage
	 * @param string wt
	 */
	function openpage($wt) {
		if (strlen($this->imdbID) != 7) {
			echo "没有该ID的IMDb条目： " . $this->imdbID . "<br />" . strlen($this->imdbID);
			$this->page[$wt] = "不能打开页面";
			return;
		}
		switch ($wt) {
			case "Title" : $urlname = "/";
				break;
			case "Credits" : $urlname = "/fullcredits";
				break;
			case "Plot" : $urlname = "/plotsummary";
				break;
			case "Taglines": $urlname = "/taglines";
				break;
		}
		if ($this->usecache) {
			@$fp = fopen("$this->cachedir/$this->imdbID.$wt", "r");
			if ($fp) {
				$temp = "";
				while (!feof($fp)) {
					$temp .= fread($fp, 1024);
				}
				if ($temp) {
					$this->page[$wt] = $temp;
					return;
				}
			}
		} // end cache

		$req = new IMDB_Request("");
		$req->setURL("http://" . $this->imdbsite . "/?plot=full&i=tt" . $this->imdbID);
		$response = $req->send();
		$responseBody = $response->getBody();
		if ($responseBody) {
			$this->page[$wt] = utf8_encode($responseBody);
		}
		if ($this->page[$wt]) { //storecache
			if ($this->storecache) {
				$fp = fopen("$this->cachedir/$this->imdbID.$wt", "w");
				fputs($fp, $this->page[$wt]);
				fclose($fp);
			}
			return;
		}
		$this->page[$wt] = "不能打开页面";
		//echo "page not found";
	}

	/** Retrieve the IMDB ID
	 * @method imdbid
	 * @return string id
	 */
	function imdbid() {
		return $this->imdbID;
	}

	/** Setup class for a new IMDB id
	 * @method setid
	 * @param string id
	 */
	function setid($id) {
		$this->imdbID = $id;

		$this->page["Title"] = "";
		$this->page["Credits"] = "";
		$this->page["Amazon"] = "";
		$this->page["Goofs"] = "";
		$this->page["Plot"] = "";
		$this->page["Comments"] = "";
		$this->page["Quotes"] = "";
		$this->page["Taglines"] = "";
		$this->page["Plotoutline"] = "";
		$this->page["Trivia"] = "";
		$this->page["Directed"] = "";

		$this->main_title = "";
		$this->main_year = "";
		$this->main_runtime = "";
		$this->main_rating = "";
		$this->main_comment = "";
		$this->main_votes = "";
		$this->main_language = "";
		$this->main_genre = "";
		$this->main_genres = "";
		$this->main_tagline = "";
		$this->main_plotoutline = "";
		$this->main_alttitle = "";
		$this->main_colors = "";
		$this->credits_cast = "";
		$this->main_director = "";
		$this->main_creator = "";

		unset($this->similiar_movies);
		$this->info_excer = new info_extractor();
	}

	/** Initialize class
	 * @constructor imdb
	 * @param string id
	 */
	function imdb($id) {
		$this->imdb_config();
		$this->setid($id);
		//if ($this->storecache && ($this->cache_expire > 0))
		//	$this->purge(true);
	}

	/** Check cache and purge outdated files
	 *  This method looks for files older than the cache_expire set in the
	 *  imdb_config and removes them
	 * @method purge
	 */
	function purge($explicit = false) {
		if (is_dir($this->cachedir)) {
			$thisdir = dir($this->cachedir);
			$now = time();
			while ($file = $thisdir->read()) {
				if ($file != "." && $file != "..") {
					$fname = $this->cachedir . "/" . $file;
					if (is_dir($fname))
						continue;
					$mod = filemtime($fname);
					if ($mod && (($now - $mod > $this->cache_expire) || $explicit == true)) {
						unlink($fname);
					}
				}
			}
		}
	}

	/** Check cache and purge outdated single imdb title file
	 *  This method looks for files older than the cache_expire set in the
	 *  imdb_config and removes them
	 * @method purge
	 */
	function purge_single($explicit = false) {
		if (is_dir($this->cachedir)) {
			$thisdir = dir($this->cachedir);
			foreach ($this->extension as $ext) {
				$fname = $this->cachedir . "/" . $this->imdbid() . "." . $ext;
				$iname = "/imdb/images/" . $this->imdbid() . ".jpg";
				//return $fname;
				if (file_exists($fname)) {
					$now = time();
					$mod = filemtime($fname);
					if ($mod && (($now - $mod > $this->cache_expire) || $explicit == true)) {
						unlink($fname);
						unlink($iname);
					}
				}
			}
		}
	}

	/** get the time that cache is stored
	 * @method getcachetime
	 */
	function getcachetime() {
		$mod = 0;
		if (is_dir($this->cachedir)) {
			$thisdir = dir($this->cachedir);
			foreach ($this->extension as $ext) {
				$fname = $this->cachedir . "/" . $this->imdbid() . "." . $ext;
				if (file_exists($fname)) {
					if ($mod > filemtime($fname) || $mod == 0)
						$mod = filemtime($fname);
				}
			}
		}
		return $mod;
	}

	/** Set up the URL to the movie title page
	 * @method main_url
	 * @return string url
	 */
	function main_url() {
		return "http://" . $this->imdbsite . "/?plot=full&i=tt" . $this->imdbid() . "/";
	}

	/** Get movie title
	 * @method title
	 * @return string title
	 */
	function title() {
		if ($this->main_title == "") {
			if ($this->page["Title"] == "") {
				$this->openpage("Title");
			}
			$data = json_decode($this->page['Title']);
			$this->main_title = $data->Title;
		}
		return $this->main_title;
	}

	/** Get year
	 * @method year
	 * @return string year
	 */
	function year() {
		if ($this->main_year == "") {
			if ($this->page["Title"] == "") {
				$this->openpage("Title");
			}
			$data = json_decode($this->page['Title']);
			$this->main_year = $data->Released;
		}
		return $this->main_year;
	}

	/** Get general runtime
	 * @method runtime_all
	 * @return string runtime
	 */
	function runtime() {
		if ($this->main_runtime == "") {
			if ($this->page["Title"] == "") {
				$this->openpage("Title");
			}
			$data = json_decode($this->page['Title']);
			$this->main_runtime = $data->Runtime;
		}
		return $this->main_runtime;
	}

	/** Get movie rating
	 * @method rating
	 * @return string rating
	 */
	function rating() {
		if ($this->main_rating == "") {
			if ($this->page["Title"] == "") {
				$this->openpage("Title");
			}
			$data = json_decode($this->page['Title']);
			$this->main_rating = $data->imdbRating;
		}
		return $this->main_rating;
	}

	/** Return votes for this movie
	 * @method votes
	 * @return string votes
	 */
	function votes() {
		if ($this->main_votes == "") {
			if ($this->page["Title"] == "") {
				$this->openpage("Title");
			}
			$data = json_decode($this->page['Title']);
			$this->main_votes = $data->imdbVotes;
		}
		return $this->main_votes;
	}

	/** Get movies original language
	 * @method language
	 * @return string language
	 */
	function language() {
		if ($this->main_language == "") {
			if ($this->page["Title"] == "") {
				$this->openpage("Title");
			}
			$data = json_decode($this->page['Title']);
			$this->main_language = $data->Language;
		}
		return $this->main_language;
	}

	/** Get the movies main genre
	 * @method genre
	 * @return string genre
	 */
	function genre() {
		if ($this->main_genre == "") {
			if ($this->page["Title"] == "") {
				$this->openpage("Title");
			}
			$data = json_decode($this->page['Title']);
			$genre = explode(",", $data->Genre);
			$this->main_genre = $genre;
		}
		return $this->main_genre;
	}

	/** Get the main Plot outline for the movie
	 * @method plotoutline
	 * @return string plotoutline
	 */
	function plotoutline() {
		if ($this->main_plotoutline == "") {
			if ($this->page["Title"] == "") {
				$this->openpage("Title");
			}
			$data = json_decode($this->page['Title']);
			$this->main_plotoutline = $data->Plot;
		}
		return $this->main_plotoutline;
	}

	/** Get rows for a given table on the page
	 * @method get_table_rows
	 * @param string html
	 * @param string table_start
	 * @return mixed rows (FALSE if table not found, array[0..n] of strings otherwise)
	 */
	function get_table_rows($html, $table_start) {
		$row_s = strpos($html, ">" . $table_start . "<");
		$row_e = $row_s;
		if ($row_s == 0)
			return FALSE;
		$endtable = strpos($html, "</table>", $row_s);
		$i = 0;
		while (($row_e + 5 < $endtable) && ($row_s != 0)) {
			$row_s = strpos($html, "<tr>", $row_s);
			$row_e = strpos($html, "</tr>", $row_s);
			$temp = trim(substr($html, $row_s + 4, $row_e - $row_s - 4));
			if (strncmp($temp, "<td valign=", 10) == 0) {
				$rows[$i] = $temp;
				$i++;
			}
			$row_s = $row_e;
		}
		return $rows;
	}

	/** Get rows for the cast table on the page
	 * @method get_table_rows_cast
	 * @param string html
	 * @param string table_start
	 * @return mixed rows (FALSE if table not found, array[0..n] of strings otherwise)
	 */
	function get_table_rows_cast($html, $table_start) {
		$row_s = strpos($html, '<table class="cast">');
		$row_e = $row_s;
		if ($row_s == 0)
			return FALSE;
		$endtable = strpos($html, "</table>", $row_s);
		$i = 0;
		while (($row_e + 5 < $endtable) && ($row_s != 0)) {
			$row_s = strpos($html, "<tr", $row_s);
			$row_e = strpos($html, "</tr>", $row_s);
			$temp = trim(substr($html, $row_s, $row_e - $row_s));
#     $row_x = strpos( $temp, '<td valign="middle"' );
			$row_x = strpos($temp, '<td class="nm">');
			$temp = trim(substr($temp, $row_x));
			if (strncmp($temp, "<td class=", 10) == 0) {
				$rows[$i] = $temp;
				$i++;
			}
			$row_s = $row_e;
		}
		return $rows;
	}

	/** Get content of table row cells
	 * @method get_row_cels
	 * @param string row (as returned by imdb::get_table_rows)
	 * @return array cells (array[0..n] of strings)
	 */
	function get_row_cels($row) {
		$cel_s = 0;
		$cel_e = 0;
		$endrow = strlen($row);
		$i = 0;
		$cels = array();
		while ($cel_e + 5 < $endrow) {
			$cel_s = strpos($row, "<td", $cel_s);
			$cel_s = strpos($row, ">", $cel_s);
			$cel_e = strpos($row, "</td>", $cel_s);
			$cels[$i] = substr($row, $cel_s + 1, $cel_e - $cel_s - 1);
			$i++;
		}
		return $cels;
	}

	/** Get the IMDB name (?)
	 * @method get_imdbname
	 * @param string href
	 * @return string
	 */
	function get_imdbname($href) {
		if (strlen($href) == 0)
			return $href;
		$name_s = 15;
		$name_e = strpos($href, '"', $name_s);
		if ($name_e != 0) {
			return substr($href, $name_s, $name_e - 1 - $name_s);
		} else {
			return $href;
		}
	}

	/** Get the director(s) of the movie
	 * @method director
	 * @return array director (array[0..n] of strings)
	 */
	function director() {
		if ($this->credits_director == "") {
			if ($this->page["Title"] == "") {
				$this->openpage("Title");
			}
			$data = json_decode($this->page["Title"]);
			$this->credits_director = $data->Director;
		}
		return $this->credits_director;
	}

	/** Get the actors
	 * @method cast
	 * @return array cast (array[0..n] of strings)
	 */
	function cast() {
		if ($this->credits_cast == "") {
			if ($this->page["Title"] == "") {
				$this->openpage("Title");
			}
			$data = json_decode($this->page["Title"]);
			$this->credits_cast = $data->Actors;
		}
		return $this->credits_cast;
	}

	/** Get cover photo
	 * @method photo
	 * @return mixed photo (string url if found, FALSE otherwise)
	 */
	function photo() {
		if ($this->main_photo == "") {
			if ($this->page["Title"] == "") {
				$this->openpage("Title");
			}
			$data = json_decode($this->page['Title']);
			$this->main_photo = $data->Poster;
		}
		return $this->main_photo;
	}

	/** Save the photo to disk
	 * @method savephoto
	 * @param string path
	 * @return boolean success
	 */
	function savephoto($path) {
		$req = new IMDB_Request("");
		$photo_url = $this->photo();
		if ($photo_url == 'N/A' || $photo_url == '')
			return FALSE;
		$req->setUrl($photo_url);
		$response = $req->send();
		if (strpos($response->getHeader("Content-Type"), 'image/jpeg') === 0 || strpos($response->getHeader("Content-Type"), 'image/gif') === 0 || strpos($response->getHeader("Content-Type"), 'image/bmp') === 0) {
			$fp = $response->getBody();
		} else {
			return FALSE;
		}

		$fp2 = fopen($path, "w");
		if ((!$fp) || (!$fp2)) {
			echo "image error...<BR>";
			return FALSE;
		}

		fputs($fp2, $fp);
		return TRUE;
	}

	/** Get the URL for the movies cover photo
	 * @method photo_localurl
	 * @return mixed url (string URL or FALSE if none)
	 */
	function photo_localurl() {
		$path = $this->photodir . $this->imdbid() . ".jpg";
		if (@fopen($path, "r"))
			return $this->photoroot . $this->imdbid() . '.jpg';
		if ($this->savephoto($path))
			return $this->photoroot . $this->imdbid() . '.jpg';
		return FALSE;
	}

	/** Get country of production
	 * @method country
	 * @return array country (array[0..n] of string)
	 */
	function country() {
		if ($this->main_country == "") {
			if ($this->page["Title"] == "") {
				$this->openpage("Title");
			}
			$data = json_decode($this->page['Title']);
			$country = explode(",", $data->Country);
			$this->main_country = $country;
		}
		return $this->main_country;
	}

}

// end class imdb
#====================================================[ IMDB Search class ]===
/** Search the IMDB for a title and obtain the movies IMDB ID
 * @package Api
 * @class imdbsearch
 * @extends imdb_config
 */
class imdbsearch extends imdb_config {

	var $page = "";
	var $name = NULL;
	var $resu = array();
	var $url = "http://www.imdb.com/";

	/** Read the config
	 * @constructor imdbsearch
	 */
	function imdbsearch() {
		$this->imdb_config();
	}

	/** Set the name (title) to search for
	 * @method setsearchname
	 */
	function setsearchname($name) {
		$this->name = $name;
		$this->page = "";
		$this->url = NULL;
	}

	/** Set the URL
	 * @method seturl
	 */
	function seturl($url) {
		$this->url = $url;
	}

	/** Create the IMDB URL for the movie search
	 * @method mkurl
	 * @return string url
	 */
	function mkurl() {
		if ($this->url !== NULL) {
			$url = $this->url;
		} else {
			if (!isset($this->maxresults))
				$this->maxresults = 20;
			switch ($this->searchvariant) {
				case "moonface" : $query = ";more=tt;nr=1"; // @moonface variant (untested)
				case "sevec" : $query = "&restrict=Movies+only&GO.x=0&GO.y=0&GO=search;tt=1"; // Sevec ori
				default : $query = ";tt=on"; // Izzy
			}
			if ($this->maxresults > 0)
				$query .= ";mx=20";
			$url = "http://" . $this->imdbsite . "/find?q=" . rawurlencode($this->name) . $query;
		}
		return $url;
	}

	/** Setup search results
	 * @method results
	 * @return array results
	 */
	function results($url = "") {
		if ($this->page == "") {
			if (empty($url))
				$url = $this->mkurl();
			$be = new IMDB_Request($url);
			$be->sendrequest();
			$fp = $be->getResponseBody();
			if (!$fp) {
				if ($header = $be->getResponseHeader("Location")) {
					if (strpos($header, $this->imdbsite . "/find?")) {
						return $this->results($header);
						break(4);
					}
					#--- @moonface variant (not tested)
					# $idpos = strpos($header, "/Title?") + 7;
					# $this->resu[0] = new imdb( substr($header, $idpos,7));
					#--- end @moonface / start sevec variant
					$url = explode("/", $header);
					$id = substr($url[count($url) - 2], 2);
					$this->resu[0] = new imdb($id);
					#--- end Sevec variant
					return $this->resu;
				} else {
					return NULL;
				}
			}
			$this->page = $fp;
		} // end (page="")

		$searchstring = array('<A HREF="/title/tt', '<A href="/title/tt', '<a href="/Title?', '<a href="/title/tt');
		$i = 0;
		foreach ($searchstring as $srch) {
			$res_e = 0;
			$res_s = 0;
			$len = strlen($srch);
			while ((($res_s = strpos($this->page, $srch, $res_e)) > 10)) {
				$res_e = strpos($this->page, "(", $res_s);
				$tmpres = new imdb(substr($this->page, $res_s + $len, 7)); // make a new imdb object by id
				$ts = strpos($this->page, ">", $res_s) + 1; // >movie title</a>
				$te = strpos($this->page, "<", $ts);
				$tmpres->main_title = substr($this->page, $ts, $te - $ts);
				$ts = strpos($this->page, "(", $te) + 1;
				$te = strpos($this->page, ")", $ts);
				$tmpres->main_year = substr($this->page, $ts, $te - $ts);
				$i++;
				$this->resu[$i] = $tmpres;
			}
		}
		return $this->resu;
	}

}

// end class imdbsearch
